package dal;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import entities.Entity;
import entities.Movie;
import entities.Show;
import entities.Theater;

public class GeneralManage
{
	private SessionFactory			factory;
	private static GeneralManage	instance;

	@SuppressWarnings("deprecation")
	private GeneralManage()
	{
		try
		{
			factory = new Configuration().configure().buildSessionFactory();
		} catch (Throwable ex)
		{
			System.err.println("Failed to create sessionFactory object." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static GeneralManage getInstance()
	{
		if (instance == null)
		{
			instance = new GeneralManage();
		}

		return instance;
	}

	public ArrayList<Integer> add(ArrayList<Entity> entitiesToAdd)
	{
		ArrayList<Integer> IDsAdded = new ArrayList<Integer>();

		for (Entity entityToAdd : entitiesToAdd)
		{
			IDsAdded.add(this.add(entityToAdd));
		}

		return IDsAdded;
	}

	public Integer add(Entity entityToAdd)
	{
		Session session = factory.openSession();
		Transaction tx = null;
		Integer objectID = null;

		try
		{
			tx = session.beginTransaction();
			objectID = (Integer) session.save(entityToAdd);
			tx.commit();
		} catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally
		{
			session.close();
		}
		return objectID;
	}

	@SuppressWarnings("rawtypes")
	public List get(Class entity, ArrayList<Class> byType,
					ArrayList<ArrayList<Entity>> byEntity)
	{
		List entitiesList = null;
		
		if(byType.isEmpty())
		{
			entitiesList = getAll(entity);
		}
		else
		{
			entitiesList = getBy(entity, byType, byEntity);
		}
		
		return entitiesList;
	}
	
	/** getBy Section **/
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private List getBy(Class entity, ArrayList<Class> byType,
			ArrayList<ArrayList<Entity>> byEntity)
	{
		ArrayList<Object> objects = null;
		Session session = factory.openSession();
		Transaction tx = null;
		Query q = null;

		String reqEntity;
		String filters;

		try
		{
			tx = session.beginTransaction();

			reqEntity = getTableAliasName(entity);
			filters = getFilters(byType, byEntity);

			q = session.createQuery("SELECT DISTINCT " + reqEntity + " "
					+ "FROM entities.Movie m, " + "entities.Show s,"
					+ "entities.Theater t " + "WHERE t.id = s.showTheater "
					+ "and   m.id = s.showMovie " + filters);

			objects = (ArrayList<Object>) q.list();
			tx.commit();

		} catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally
		{
			session.close();
		}
		
		return objects;
	}

	@SuppressWarnings("rawtypes")
	private String getTableAliasName(Class entity)
	{
		String aliasName = null;

		if (entity == Movie.class)
		{
			aliasName = "m";
		} else if (entity == Theater.class)
		{
			aliasName = "t";
		} else if (entity == Show.class)
		{
			aliasName = "s";
		}

		return aliasName;
	}

	@SuppressWarnings("rawtypes")
	private String getFilters(ArrayList<Class> byTypes,
			ArrayList<ArrayList<Entity>> byEntities)
	{
		String filters = "";

		if (!byTypes.isEmpty())
		{
			for (Class byType : byTypes)
			{
				filters += " and " + getFilter(byType, byEntities.get(byTypes.indexOf(byType)));
			}
		}
		
		return filters;
	}

	@SuppressWarnings("rawtypes")
	private String getFilter(Class byType, ArrayList<Entity> btEntities)
	{
		String filter = getIDColumnName(byType) + " in (";

		for (Entity byEntity : btEntities)
		{
			filter += byEntity.getID() + ",";
		}

		filter += ")";
		filter = filter.replace(",)", ") ");

		return filter;
	}

	@SuppressWarnings("rawtypes")
	private String getIDColumnName(Class entity)
	{
		String idColumnName = null;

		if (entity == Movie.class)
		{
			idColumnName = "movie_id";
		} else if (entity == Theater.class)
		{
			idColumnName = "theater_id";
		} else if (entity == Show.class)
		{
			idColumnName = "id";
		}

		return idColumnName;
	}

	/** end of getBy section **/
	
	@SuppressWarnings({ "rawtypes" })
	public List getAll(Class entity)
	{
		List objects = null;
		Session session = factory.openSession();
		Transaction tx = null;
		try
		{
			tx = session.beginTransaction();
			objects = session.createQuery("FROM " + entity.getName()).list();
			tx.commit();
		} catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally
		{
			session.close();
		}
		return objects;
	}

	@SuppressWarnings("rawtypes")
	public void delete(Class entityToDelete, Integer entityID)
	{
		Session session = factory.openSession();
		Transaction tx = null;
		try
		{
			tx = session.beginTransaction();
			Object object = (Object) session.get(entityToDelete, entityID);
			session.delete(object);
			tx.commit();
		} catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally
		{
			session.close();
		}
	}
}
